package com.chens.common.filter;

import com.chens.common.exception.UnauthorizedException;
import com.chens.common.security.JwtTokenUtils;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

/**
 * JWT认证过滤器
 * @description 用于所有请求进来之前，从请求头中解析JWT令牌并进行认证
 * @author chensh
 * @date 2025/08/01 16:22
 */
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    private final JwtTokenUtils jwtTokenUtils;

    private final UserDetailsService userDetailsService;

    @Autowired
    public JwtAuthenticationFilter(JwtTokenUtils jwtTokenUtils, UserDetailsService userDetailsService) {
        this.jwtTokenUtils = jwtTokenUtils;
        this.userDetailsService = userDetailsService;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        // 从 request 获取 JWT token
        String jwt = jwtTokenUtils.getJwtFromRequest(request);

        if (StringUtils.hasText(jwt)) {
            // 验证 JWT token
            if (!jwtTokenUtils.validateToken(jwt)) {
                throw new UnauthorizedException("Invalid or expired JWT token");
            }

            // 从 JWT token 中获取用户名
            String username = jwtTokenUtils.getUsernameFromJWT(jwt);
            // 从数据库中查询用户信息
            UserDetails userDetails = userDetailsService.loadUserByUsername(username);
            // 创建认证对象
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                    userDetails, null, userDetails.getAuthorities());
            // 设置认证详情
            authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

            // 将认证对象设置到 SecurityContextHolder 中
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }

        filterChain.doFilter(request, response);
    }
}